#include "gtest/gtest.h"
#include "../BaseUtil/MyTest.h"
#include "Coverage.hpp"
namespace TestingCoverage {

TEST(CoverageTest, SelectOneHeteroVectorFromSeveral) {
	typedef LOKI_TYPELIST_2(int, int) MyInputTypes;

	int arg1[] = { 1, 2 };
	int arg2[] = { 3, 4 };

	HeteroVector< MyInputTypes > heteroVector;
	heteroVector.set< 0 >( arg1 );
	heteroVector.set< 1 >( arg2 );

	HeteroVector< MyInputTypes > rst1 = oneHeteroVectorAt(heteroVector, 0);
	ASSERT_EQ( 1u, rst1.size< 0 >() );
	ASSERT_EQ( 1u, rst1.size< 1 >() );
	ASSERT_EQ( 1, rst1.get< 0 >( 0 ) );
	ASSERT_EQ( 3, rst1.get< 1 >( 0 ) );

	HeteroVector< MyInputTypes > rst2 = oneHeteroVectorAt(heteroVector, 1);
	ASSERT_EQ( 1u, rst2.size< 0 >() );
	ASSERT_EQ( 1u, rst2.size< 1 >() );
	ASSERT_EQ( 2, rst2.get< 0 >( 0 ) );
	ASSERT_EQ( 4, rst2.get< 1 >( 0 ) );
}

TEST(CoverageTest, CombineHeteroVectorFunctorTest) {
	typedef LOKI_TYPELIST_1(int) MyInputTypes;

	HeteroVector< MyInputTypes > heteroVector1;
	int arg1[] = { 1, 2 };
	heteroVector1.set< 0 >( arg1 );

	HeteroVector< MyInputTypes > heteroVector2;
	int arg2[] = { 3, 4, 5 };
	heteroVector2.set< 0 >( arg2 );

	HeteroVector< MyInputTypes > rst = combineHeteroVector(heteroVector1, heteroVector2);

	ASSERT_EQ(5u, rst.size< 0 >());
	ASSERT_EQ(1, rst.get<0>(0));
	ASSERT_EQ(2, rst.get<0>(1));
	ASSERT_EQ(3, rst.get<0>(2));
	ASSERT_EQ(4, rst.get<0>(3));
	ASSERT_EQ(5, rst.get<0>(4));
}

bool switchOnOff( bool switch1, bool switch2, bool switch3 ) {
	return switch1 && (switch2 || switch3);
}

TEST(CoverageTest, AllCombinationsCoverage) {
	typedef LOKI_TYPELIST_3(bool, bool, bool) Booleans;
	enum { switch1, switch2, switch3 };
	HeteroVector< Booleans > inputs;

	bool true_false[] = { true, false };
	bool true_only[]  = { true };

	inputs.set< switch1 >( true_false );
	inputs.set< switch2 >( true_only );
	inputs.set< switch3 >( true_false );
	const bool expected[] = {
			/*TTT*/ true,
			/*FTT*/ false,
			/*TTF*/ true,
			/*FTF*/ false };

	HeteroVector< Booleans > ACoC = allCombinationsCoverage(inputs);
	ASSERT_EQ(sizeof(expected)/sizeof(bool), ACoC.size< switch1 >());
	ASSERT_TRUE( ACoC.size< switch1 >() == ACoC.size< switch2 >() );
	ASSERT_TRUE( ACoC.size< switch2 >() == ACoC.size< switch3 >() );

	for(unsigned int idx = 0; idx < ACoC.size< switch1 >(); ++idx)
		ASSERT_EQ( expected[idx], switchOnOff( ACoC.get< switch1 >(idx), ACoC.get< switch2 >(idx), ACoC.get< switch3 >(idx) ) ) << idx;
}

TEST(CoverageTest, BaseChoicesCoverage) {
	typedef LOKI_TYPELIST_3(bool, bool, bool) Booleans;
	enum { switch1, switch2, switch3 };
	HeteroVector< Booleans > inputs;

	bool true_false[] = { true, false };
	bool false_only[] = { false };

	inputs.set< switch1 >( true_false );
	inputs.set< switch2 >( true_false );
	inputs.set< switch3 >( false_only );
	const bool expected[] = {
			/*TTF*/ true,
			/*FTF*/ false,
			/*TFF*/ false };

	HeteroVector< Booleans > BCC = baseChoiceCoverage(inputs);
	ASSERT_EQ(sizeof(expected)/sizeof(bool), BCC.size< switch1 >());
	ASSERT_TRUE( BCC.size< switch1 >() == BCC.size< switch2 >() );
	ASSERT_TRUE( BCC.size< switch2 >() == BCC.size< switch3 >() );

	for(unsigned int idx = 0; idx < BCC.size< switch1 >(); ++idx)
		ASSERT_EQ( expected[idx], switchOnOff( BCC.get< switch1 >(idx), BCC.get< switch2 >(idx), BCC.get< switch3 >(idx) ) ) << idx;
}

TEST(CoverageTest, EachChoiceCoverage) {
//	A1x B2y A3x
}

TEST(CoverageTest, PairWiseCoverage) {
//A1, B1, 1x
//A2 B2, 1y
//A3l B3, 2x
//Ax, Bx, 2y
//Ay, By, 3x
//3y
//
//A1x B1y
//A2x B2y
//A3x B3y
//A - y, B- x
}

}
